package com.ruoyi.jt808.util.abandon;

import java.util.*;
import java.text.SimpleDateFormat;

public class JT808CompleteParser {

    // 消息头结构
    static class MessageHeader {
        public int msgId;
        public int msgBodyProps;
        public String terminalId;
        public int msgSeq;
        public boolean hasSubPackage;
        public int encryptionType;
        public int bodyLength;

        @Override
        public String toString() {
            return String.format("消息ID: 0x%04X, 终端: %s, 流水号: %d, 加密: %d, 长度: %d",
                    msgId, terminalId, msgSeq, encryptionType, bodyLength);
        }
    }

    // 位置信息结构
    static class LocationInfo {
        public long alarmFlag;
        public long status;
        public double latitude;
        public double longitude;
        public int altitude;
        public double speed;
        public int direction;
        public String time;
        public List<ExtraInfo> extraInfos = new ArrayList<>();
    }

    // 附加信息结构
    static class ExtraInfo {
        public int type;
        public int length;
        public byte[] data;
        public String description;

        public ExtraInfo(int type, int length, byte[] data) {
            this.type = type;
            this.length = length;
            this.data = data;
            this.description = parseDescription(type, data);
        }

        private String parseDescription(int type, byte[] data) {
            switch (type) {
                case 0x01: return "里程: " + bytesToLong(data) + "米";
                case 0x02: return "油量: " + ((data[0] & 0xFF) << 8 | (data[1] & 0xFF)) + "L";
                case 0x03: return "行驶记录速度: " + ((data[0] & 0xFF) << 8 | (data[1] & 0xFF)) + "km/h";
                case 0x04: return "报警事件ID: " + ((data[0] & 0xFF) << 8 | (data[1] & 0xFF));
                case 0x11: return "超速报警: " + new String(data);
                case 0x12: return "进出区域报警";
                case 0x13: return "路段行驶时间报警";
                case 0x25: return "扩展信号状态: 0x" + Long.toHexString(bytesToLong(data));
                case 0x2A: return "IO状态: 0x" + Integer.toHexString((data[0] & 0xFF) << 8 | (data[1] & 0xFF));
                case 0x2B: return "模拟量";
                case 0x30: return "信号强度: " + (data[0] & 0xFF);
                case 0x31: return "卫星数量: " + (data[0] & 0xFF);
                case 0x70: return "基站信息: " + new String(data);
                case 0xEB: return parseCustomEBInfo(data);
                case 0xC4: return parseCustomC4Info(data);
                default: return "自定义信息: " + bytesToHex(data);
            }
        }

        private String parseCustomEBInfo(byte[] data) {
            // 解析0xEB自定义信息
            StringBuilder sb = new StringBuilder("EB自定义信息: ");
            if (data.length >= 2) {
                int subType = (data[0] & 0xFF) << 8 | (data[1] & 0xFF);
                sb.append("子类型=0x").append(String.format("%04X", subType));
            }
            if (data.length > 2) {
                sb.append(", 数据=").append(bytesToHex(Arrays.copyOfRange(data, 2, data.length)));
            }
            return sb.toString();
        }

        private String parseCustomC4Info(byte[] data) {
            // 解析0xC4自定义信息
            return "C4自定义信息: " + bytesToHex(data);
        }

        @Override
        public String toString() {
            return String.format("0x%02X: %s", type, description);
        }
    }

    public static void main(String[] args) {
        String packet = "7E020000EE0610006515543A79000000000000080001FADDCD0669529A0000000000002510071141150104000021FF30011F310100EBC4000C00B28986084810247076538700060089FFFFFFFF000600C5FFFFFFF70004002D0E58000300A828000B00D801CC0090830B3D3419001100D5383631303134303738373935353937007000B90545383A32323A38313A43393A46453A44302C2D37332C34343A44463A36353A39363A37373A30322C2D37332C32343A39373A34353A34333A36363A43382C2D37342C31363A44383A36343A31303A33433A41462C2D38392C31433A37333A45323A44313A35423A32392C2D39330007002A000000000AD37E";

        try {
            parseCompletePacket(packet);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void parseCompletePacket(String packet) {
        System.out.println("=== JT808数据包完整解析 ===\n");

        // 验证数据包
        if (!packet.startsWith("7E") || !packet.endsWith("7E")) {
            System.out.println("无效数据包格式");
            return;
        }

        // 转义还原
        String content = packet.substring(2, packet.length() - 2);
        byte[] data = unescapePacket(hexStringToByteArray(content));

        // 解析消息头
        MessageHeader header = parseMessageHeader(data);
        System.out.println("【消息头信息】");
        System.out.println(header);
        System.out.println();

        // 解析位置信息报告
        if (header.msgId == 0x0200) {
            LocationInfo location = parseLocationInfo(data, header);
            printLocationInfo(location);
        }
    }

    private static MessageHeader parseMessageHeader(byte[] data) {
        MessageHeader header = new MessageHeader();
        int offset = 0;

        header.msgId = (data[offset] & 0xFF) << 8 | (data[offset + 1] & 0xFF);
        offset += 2;

        header.msgBodyProps = (data[offset] & 0xFF) << 8 | (data[offset + 1] & 0xFF);
        offset += 2;

        // 解析消息体属性
        header.bodyLength = header.msgBodyProps & 0x03FF; // 低10位为长度
        header.hasSubPackage = ((header.msgBodyProps >> 13) & 0x01) == 1;
        header.encryptionType = (header.msgBodyProps >> 10) & 0x07;

        // 终端手机号
        StringBuilder terminalId = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            terminalId.append(String.format("%02X", data[offset + i]));
        }
        header.terminalId = terminalId.toString();
        offset += 6;

        // 消息流水号
        header.msgSeq = (data[offset] & 0xFF) << 8 | (data[offset + 1] & 0xFF);

        return header;
    }

    private static LocationInfo parseLocationInfo(byte[] data, MessageHeader header) {
        LocationInfo location = new LocationInfo();
        int offset = 12; // 消息头长度

        // 报警标志
        location.alarmFlag = 0;
        for (int i = 0; i < 4; i++) {
            location.alarmFlag = (location.alarmFlag << 8) | (data[offset + i] & 0xFF);
        }
        offset += 4;

        // 状态
        location.status = 0;
        for (int i = 0; i < 4; i++) {
            location.status = (location.status << 8) | (data[offset + i] & 0xFF);
        }
        offset += 4;

        // 纬度
        int latitude = (data[offset] & 0xFF) << 24 | (data[offset + 1] & 0xFF) << 16 |
                (data[offset + 2] & 0xFF) << 8 | (data[offset + 3] & 0xFF);
        location.latitude = latitude / 1000000.0;
        offset += 4;

        // 经度
        int longitude = (data[offset] & 0xFF) << 24 | (data[offset + 1] & 0xFF) << 16 |
                (data[offset + 2] & 0xFF) << 8 | (data[offset + 3] & 0xFF);
        location.longitude = longitude / 1000000.0;
        offset += 4;

        // 高程
        location.altitude = (data[offset] & 0xFF) << 8 | (data[offset + 1] & 0xFF);
        offset += 2;

        // 速度
        int speed = (data[offset] & 0xFF) << 8 | (data[offset + 1] & 0xFF);
        location.speed = speed / 10.0;
        offset += 2;

        // 方向
        location.direction = (data[offset] & 0xFF) << 8 | (data[offset + 1] & 0xFF);
        offset += 2;

        // 时间
        String timeBcd = bcdToString(data, offset, 6);
        location.time = "20" + timeBcd.substring(0, 2) + "-" + timeBcd.substring(2, 4) + "-" +
                timeBcd.substring(4, 6) + " " + timeBcd.substring(6, 8) + ":" +
                timeBcd.substring(8, 10) + ":" + timeBcd.substring(10, 12);
        offset += 6;

        // 解析附加信息
        location.extraInfos = parseAllExtraInfo(data, offset);

        return location;
    }

    private static List<ExtraInfo> parseAllExtraInfo(byte[] data, int offset) {
        List<ExtraInfo> extraInfos = new ArrayList<>();

        while (offset < data.length) {
            int type = data[offset] & 0xFF;
            if (type == 0) break; // 结束标志

            int length = data[offset + 1] & 0xFF;
            byte[] extraData = new byte[length];

            if (offset + 2 + length <= data.length) {
                System.arraycopy(data, offset + 2, extraData, 0, length);
                extraInfos.add(new ExtraInfo(type, length, extraData));
            }

            offset += 2 + length;
        }

        return extraInfos;
    }

    private static void printLocationInfo(LocationInfo location) {
        System.out.println("【位置基本信息】");
        System.out.printf("报警标志: 0x%08X\n", location.alarmFlag);
        printAlarmInfo(location.alarmFlag);

        System.out.printf("状态: 0x%08X\n", location.status);
        printStatusInfo(location.status);

        System.out.printf("纬度: %.6f°\n", location.latitude);
        System.out.printf("经度: %.6f°\n", location.longitude);
        System.out.printf("高程: %d米\n", location.altitude);
        System.out.printf("速度: %.1fkm/h\n", location.speed);
        System.out.printf("方向: %d°\n", location.direction);
        System.out.printf("时间: %s\n", location.time);

        System.out.println("\n【附加信息列表】");
        for (ExtraInfo extra : location.extraInfos) {
            System.out.println(extra);

            // 详细解析特定自定义信息
            if (extra.type == 0xEB) {
                parseEBDetail(extra.data);
            } else if (extra.type == 0xC4) {
                parseC4Detail(extra.data);
            }
        }
    }

    private static void parseEBDetail(byte[] data) {
        System.out.println("  └─ EB详细信息:");
        System.out.printf("     数据长度: %d字节\n", data.length);
        System.out.printf("     原始数据: %s\n", bytesToHex(data));

        if (data.length >= 14) {
            // 详细解析EB数据结构
            int subType = (data[0] & 0xFF) << 8 | (data[1] & 0xFF);
            int field1 = (data[2] & 0xFF) << 8 | (data[3] & 0xFF);
            int field2 = (data[4] & 0xFF) << 8 | (data[5] & 0xFF);
            int field3 = (data[6] & 0xFF) << 8 | (data[7] & 0xFF);
            int field4 = (data[8] & 0xFF) << 8 | (data[9] & 0xFF);
            int field5 = (data[10] & 0xFF) << 8 | (data[11] & 0xFF);
            int field6 = (data[12] & 0xFF) << 8 | (data[13] & 0xFF);

            System.out.printf("     子类型: 0x%04X\n", subType);
            System.out.printf("     字段1: 0x%04X\n", field1);
            System.out.printf("     字段2: 0x%04X\n", field2);
            System.out.printf("     字段3: 0x%04X\n", field3);
            System.out.printf("     字段4: 0x%04X\n", field4);
            System.out.printf("     字段5: 0x%04X\n", field5);
            System.out.printf("     字段6: 0x%04X\n", field6);
        }
    }

    private static void parseC4Detail(byte[] data) {
        System.out.println("  └─ C4详细信息:");
        System.out.printf("     数据长度: %d字节\n", data.length);
        System.out.printf("     原始数据: %s\n", bytesToHex(data));
    }

    private static void printAlarmInfo(long alarmFlag) {
        String[] alarms = {
                "紧急报警", "超速报警", "疲劳驾驶", "危险预警",
                "GNSS模块故障", "GNSS天线短路", "GNSS天线开路", "终端主电源欠压",
                "终端主电源掉电", "终端LCD或显示器故障", "TTS模块故障", "摄像头故障"
        };

        System.out.print("     报警详情: ");
        for (int i = 0; i < Math.min(alarms.length, 32); i++) {
            if (((alarmFlag >> i) & 1) == 1) {
                System.out.print(alarms[i] + " ");
            }
        }
        System.out.println();
    }

    private static void printStatusInfo(long status) {
        System.out.print("     状态详情: ");
        if ((status & 0x0001) != 0) System.out.print("ACC开 ");
        if ((status & 0x0002) != 0) System.out.print("定位 ");
        if ((status & 0x0004) != 0) System.out.print("南纬 ");
        if ((status & 0x0008) != 0) System.out.print("西经 ");
        if ((status & 0x0010) != 0) System.out.print("停运 ");
        if ((status & 0x0020) != 0) System.out.print("加密 ");
        System.out.println();
    }

    // 工具方法
    private static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }

    private static byte[] unescapePacket(byte[] data) {
        List<Byte> result = new ArrayList<>();
        for (int i = 0; i < data.length; i++) {
            if (data[i] == 0x7D) {
                if (i + 1 < data.length) {
                    if (data[i + 1] == 0x01) {
                        result.add((byte) 0x7D);
                    } else if (data[i + 1] == 0x02) {
                        result.add((byte) 0x7E);
                    }
                    i++;
                }
            } else {
                result.add(data[i]);
            }
        }

        byte[] unescaped = new byte[result.size()];
        for (int i = 0; i < result.size(); i++) {
            unescaped[i] = result.get(i);
        }
        return unescaped;
    }

    private static String bcdToString(byte[] data, int offset, int length) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(String.format("%02X", data[offset + i]));
        }
        return sb.toString();
    }

    private static long bytesToLong(byte[] data) {
        long value = 0;
        for (byte b : data) {
            value = (value << 8) | (b & 0xFF);
        }
        return value;
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b));
        }
        return sb.toString().trim();
    }
}